﻿#ifndef __INC_QGACH_H__
#define __INC_QGACH_H__

#ifdef _MSC_VER
#pragma once
#pragma warning(push)
#pragma warning(disable:4251)
#endif

#include <float.h>
#include "qgabe.h"
#include "qguims.h"

//////////////////////////////////////////////////////////////////////////
// definition

// tm, type
enum qgTmType
{
	QGTM_WORLD,
	QGTM_VIEW,
	QGTM_PROJ,
	QGTM_TEX_0,
	QGTM_TEX_1,
	QGTM_TEX_2,
	QGTM_TEX_3,
	QGTM_TEX_4,
	QGTM_TEX_5,
	QGTM_TEX_6,
	QGTM_TEX_7,
	QGTM_MAX_VALUE
};

// color, format
enum qgColorFormat
{
	QGCF_NONE,

	QGCF8_L,			// l8
	QGCF16_L,			// l16

	QGCF16_RGB,			// r5 g6 b5
	QGCF16_RGBA,		// a1 r5 b5 g5

	QGCF32_RGB,			// x8 r8 g8 b8
	QGCF32_RGBA,		// a8 r8 g8 b8
	QGCF32_BGR,			// x8 b8 g8 r8
	QGCF32_BGRA,		// a8 b8 g8 r8

	QGCF16F_R,			// r16
	QGCF64F_BGRA,		// a16 b16 g16 r16

	QGCF32F_R,			// r32
	QGCF128F_BGRA,		// a32 b32 g32 r32

	QGCF_DXT1,
	QGCF_DXT2,			// do not use
	QGCF_DXT3,
	QGCF_DXT4,			// do not use
	QGCF_DXT5,

	QGCF_MAX_VALUE
};

// color, flag
enum qgColorFlag
{
	QGCFF_NONE = 0,
	QGCFF_ALPHA = 0x0001,
	QGCFF_COMPRESS = 0x0002,
	QGCFF_FLOAT = 0x0004,
	QGCFF_BGR = 0x0008,
};

// color, mask
enum qgColorMask
{
	QGCM_RED = 1,
	QGCM_GREEN = 2,
	QGCM_BLUE = 4,
	QGCM_ALPHA = 8,

	QGCM_RGB = QGCM_RED | QGCM_GREEN | QGCM_BLUE,
	QGCM_RGBA = QGCM_RED | QGCM_GREEN | QGCM_BLUE | QGCM_ALPHA,
	QGCM_NONE = 0,
};

// compare op
enum qgCmpOp
{
	QGCOP_NEVER,
	QGCOP_LE,
	QGCOP_EQ,
	QGCOP_LEQ,
	QGCOP_GR,
	QGCOP_NEQ,
	QGCOP_GEQ,
	QGCOP_ALWAYS
};

// stencil op
enum qgStencilOp
{
	QGSOP_KEEP,
	QGSOP_ZERO,
	QGSOP_REPLACE,
	QGSOP_SAT_INC,
	QGSOP_SAT_DEC,
	QGSOP_INVERT,
	QGSOP_INC,
	QGSOP_DEC,
};

// draw, clearance
enum qgClearance
{
	QGCLEAR_DEPTH = 1,
	QGCLEAR_STENCIL = 2,
	QGCLEAR_RENDER = 3
};

// draw, primitive topology
enum qgTopology
{
	QGTPG_POINT_LIST,
	QGTPG_LINE_LIST,
	QGTPG_LINE_STRIP,
	QGTPG_TRI_LIST,
	QGTPG_TRI_STRIP,
	//QGTPG_TRI_FAN,	// no support for D11
};

// draw, fill mode
enum qgFill
{
	QGFILL_POINT,
	QGFILL_WIRE,
	QGFILL_SOLID
};

// draw, cull mode
enum qgCull
{
	QGCULL_NONE,
	QGCULL_FRONT,
	QGCULL_BACK,
};

// texture, type
enum qgTextureType
{
	QGTEXTURE_1D,
	QGTEXTURE_2D,
	QGTEXTURE_3D,
	QGTEXTURE_CUBE,
	QGTEXTURE_2D_ARRAY,
};

// texture, flag
enum qgTextureFlag
{
	QGTEXF_NOMIP = 0x0100,			// no mipmap
	QGTEXF_ARRAY = 0x0200,			// array texture (2D)
	QGTEXF_IMAGE = 0x0400,			// keep image data
	QGTEXF_OFF = 0x8000,			// off-screen
};

// texture, filter
enum qgFilter
{
	QGFLTX_POINT,
	QGFLTX_LINEAR,
	QGFLT_MAG_MIN_MIP_POINT,
	QGFLT_MAG_MIN_POINT_MIP_LINEAR,
	QGFLT_MAG_POINT_MIN_LINEAR_MIP_POINT,
	QGFLT_MAG_POINT_MIN_MIP_LINEAR,
	QGFLT_MAG_LINEAR_MIN_MIP_POINT,
	QGFLT_MAG_LINEAR_MIN_POINT_MIP_LINEAR,
	QGFLT_MAG_MIN_LINEAR_MIP_POINT,
	QGFLT_MAG_MIN_MIP_LINEAR,
	QGFLT_ANISOTROPIC,
};

// texture, address
enum qgAddress
{
	QGADR_WRAP,
	QGADR_MIRROR,
	QGADR_CLAMP,
	QGADR_BORDER,
	QGADR_ONCE,
};

// texture, face
enum qgFacePlate
{
	QGFPL_NONE,
	QGFPL_PX,
	QGFPL_NX,
	QGFPL_PY,
	QGFPL_NY,
	QGFPL_PZ,
	QGFPL_NZ,
};

// blend, op
enum qgBlendOp
{
	QGBLO_ADD,
	QGBLO_SUB,
	QGBLO_RSUB,
	QGBLO_MIN,
	QGBLO_MAX,
};

// blend, factor
enum qgBlendFactor
{
	QGBLF_ZERO,
	QGBLF_ONE,
	QGBLF_SC,
	QGBLF_SC_INV,
	QGBLF_SA,
	QGBLF_SA_INV,
	QGBLF_DA,
	QGBLF_DA_INV,
	QGBLF_DC,
	QGBLF_DC_INV,
	QGBLF_SAS,
};

// layout, usage
enum qgLoUsage
{
	QGLOU_POSITION,
	QGLOU_COLOR,		// diffuse & specular
	QGLOU_WEIGHT,		// blend weights
	QGLOU_INDEX,		// blend indices
	QGLOU_NORMAL,
	QGLOU_TEXTURE,		// texture coord
	QGLOU_TANGENT,
	QGLOU_BINORMAL,
	QGLOU_MAX_VALUE		// sometimes uses in DX9
};

// layout, type
enum qgLoType
{
	QGLOT_FLOAT1,
	QGLOT_FLOAT2,
	QGLOT_FLOAT3,
	QGLOT_FLOAT4,
	QGLOT_HALF2,
	QGLOT_HALF4,
	QGLOT_BYTE2,
	QGLOT_BYTE4,
	QGLOT_BYTE4N,
	QGLOT_SHORT2,
	QGLOT_SHORT4,
	QGLOT_SHORT2N,
	QGLOT_COLOR,
	QGLOT_MAX_VALUE
};

// shader, type
enum qgShaderType
{
	QGSHADER_VS,
	QGSHADER_PS,
	//QGSHADER_GS,
	//QGSHADER_DS,
	//QGSHADER_HS,
	//QGSHADER_CS,
	//QGSHADER_EF,
};

// shader, role
enum qgShaderRole
{
	QGSHDR_MANUAL,
	QGSHDR_AUTO,
	QGSHDR_DISCARD,
};

// shader, data
enum qgShaderData
{
	QGSHDD_UNKNOWN,
	QGSHDD_FLOAT1,
	QGSHDD_FLOAT2,
	QGSHDD_FLOAT3,
	QGSHDD_FLOAT4,
	QGSHDD_FLOAT16,
	QGSHDD_INT1,
	QGSHDD_INT2,
	QGSHDD_INT3,
	QGSHDD_INT4,
	QGSHDD_BYTE1,
	QGSHDD_BYTE2,
	QGSHDD_BYTE3,
	QGSHDD_BYTE4,
	QGSHDD_SPLR_1D,
	QGSHDD_SPLR_2D,
	QGSHDD_SPLR_3D,
	QGSHDD_SPLR_CUBE,
	QGSHDD_MAX_VALUE
};

// shader, auto type
enum qgShaderAuto
{
	QGSHDA_ORTHO_PROJ,
	QGSHDA_WORLD,
	QGSHDA_VIEW,
	QGSHDA_PROJ,
	QGSHDA_VIEW_PROJ,
	QGSHDA_INV_VIEW,
	QGSHDA_WORLD_VIEW_PROJ,
	QGSHDA_TEX0,
	QGSHDA_TEX1,
	QGSHDA_TEX2,
	QGSHDA_TEX3,
	QGSHDA_TEX4,
	QGSHDA_TEX5,
	QGSHDA_TEX6,
	QGSHDA_TEX7,
	QGSHDA_PROP_VEC0,
	QGSHDA_PROP_VEC1,
	QGSHDA_PROP_VEC2,
	QGSHDA_PROP_VEC3,
	QGSHDA_PROP_MAT0,
	QGSHDA_PROP_MAT1,
	QGSHDA_PROP_MAT2,
	QGSHDA_PROP_MAT3,
	QGSHDA_MAT_PALETTE,
	QGSHDA_MAX_VALUE
};

// buffer, type
enum qgBufferType
{
	QGBUFFER_DATA,	// usually unknown
	QGBUFFER_INDEX,
	QGBUFFER_VERTEX,
};

// stage, texture
enum qgStageTexture
{
	QGSGTEX_1,
	QGSGTEX_2,
	QGSGTEX_3,
	QGSGTEX_4,
	QGSGTEX_5,
	QGSGTEX_6,
	QGSGTEX_7,
	QGSGTEX_8,
	QGSGTEX_MAX_VALUE
};

// stage, off texture
enum qgStageOffTexture
{
	QGSGOFF_1,
#if !_SB_MOBILE_
	QGSGOFF_2,
	QGSGOFF_3,
	QGSGOFF_4,
#endif
	QGSGOFF_MAX_VALUE
};

// stage, vertex stream
enum qgStageVertex
{
	QGSGVERT_1,
	QGSGVERT_2,
	QGSGVERT_3,
	QGSGVERT_4,
	QGSGVERT_MAX_VALUE
};

// stage, vertex layout declaration
enum qgStageVertexLayout
{
	QGSGVERTEXLAYOUT_MAX_VALUE = 10
};

// resource creation flag
enum qgResourceFlag
{
	QGRESF_NONE = 0,
	QGRESF_DYNAMIC = 0x0001,		// freq writing
	QGRESF_LOCAL = 0x0002,			// stagging (if function support)
	QGRESF_STREAM = 0x0004,			// stream (if function support)

	QGRESF_BGRA = 0x0100,			// image type is BGRA
};

// resource access flag
enum qgResourceAccess
{
	QGENTF_NONE = 0,
	QGENTF_READ = 0x0001,
	QGENTF_WRITE = 0x0002,
	QGENTF_READWRITE = (QGENTF_READ | QGENTF_WRITE),
};

// viewport
struct qbViewPort
{
	tpl::Point			loc;
	tpl::Point			size;
	tpl::Vec2			depth;
	float				aspect;
};

// screen desc
struct qbScreenDesc
{
	kint				dstn;

	kint				width;
	kint				height;
	kint				freq;

	kint				internal_fmt;
	kint				internal_type;
};

// adapter desc
struct qbAdapterDesc
{
	kint				index;
	klong				memsize;
	char				desc[K_MAX_PATH];
};

// pixel property
struct qbPixelProp
{
	qgColorFormat		fmt;
	const char*			name;
	kbyte				bpp;
	kbyte				rr, rl;
	kbyte				gr, gl;
	kbyte				br, bl;
	kbyte				ar, al;
	kint				flags;
	bool				alpha;
};

// depth stencil
struct qbDhslData
{
	bool				depth_write;
	qgCmpOp				depth_func : 8;

	bool				front_enable;
	qgCmpOp				front_func : 8;
	qgStencilOp			front_pass : 8;
	qgStencilOp			front_fail : 8;
	qgStencilOp			front_depth_fail : 8;

	bool				back_enable;
	qgCmpOp				back_func : 8;
	qgStencilOp			back_pass : 8;
	qgStencilOp			back_fail : 8;
	qgStencilOp			back_depth_fail : 8;

	kbyte				mask_read;
	kbyte				mask_write;
};

// rasterize
struct qbRaszData
{
	qgFill				fill : 8;
	qgCull				cull : 8;

	float				depth_bias;
	float				slope_scale;
};

// blend
struct qbBlndData
{
	qgBlendOp			color_op : 16;
	qgBlendFactor		color_src : 8;
	qgBlendFactor		color_dest : 8;

	qgBlendOp			alpha_op : 16;
	qgBlendFactor		alpha_src : 8;
	qgBlendFactor		alpha_dest : 8;

	qgColorMask			mask;
};

// sampler
struct qbSplrData
{
	qgFilter			filt : 8;
	qgAddress			addru : 8;
	qgAddress			addrv : 8;
	qgAddress			addrw : 8;
	qgCmpOp				cop;				// comparison function
	tpl::ColorValue		bcv;				// border color
	kint				lod_bias;			// LOD bias (MIP)
	tpl::Vec2			lod_range;			// LOD range (MIP)
};

// shader var
struct qbShaderVar
{
	ksize_t				hash;
	char				name[32];

	qgShaderRole		role : 8;
	qgShaderData		data : 8;

	kuint				size : 16;
	kuintptr			offset;

	kpointer			intr;			// auto ptr
	kpointer			ptr;			// D11, DX9 only
};

// shader auto info
struct qbShaderAutoInfo
{
	typedef void (*Function)(kpointer, const qbShaderVar&);

	ksize_t				hash;
	const char*			name;
	qgShaderAuto		type;
	Function			func;
};

// draw layout, element
struct qbLayoutElement
{
	qgLoUsage			usage : 16;
	kint				index : 16;
	qgLoType			type : 16;
	kint				slot : 16;
	kint				insts;
};

// map
struct qbTextureMap
{
	kpointer			data;
	kint				pitch;
	kint				slice;

	kint				width;
	kint				height;
	kint				depth;
};

// supp
namespace qgAchSupp
{
	K_FORCEINLINE kuint PackPixel(const qbPixelProp& prop, kbyte r, kbyte g, kbyte b, kbyte a)
	{
		return ((kuint)(
			((a >> prop.ar) << prop.al) |
			((r >> prop.rr) << prop.rl) |
			((g >> prop.gr) << prop.gl) |
			((b >> prop.br) << prop.bl)));
	}

	KAPI kbool TestAlpha(qgColorFormat fmt);
	KAPI const qbPixelProp& ToPixelProp(qgColorFormat fmt);
	KAPI kuint UnsafePackPixel(qgColorFormat fmt, kbyte r, kbyte g, kbyte b, kbyte a);

	KAPI kint LayoutTypeToSize(qgLoType type);
	KAPI const char* ShaderDataToString(qgShaderData type);
	KAPI const char* ShaderTypeToString(qgShaderType type);
}


//////////////////////////////////////////////////////////////////////////
// file wrap & service

// file wrap head
struct qbFwHsHead
{
	kuint				hdr;
	kushort				version;
	kushort				revision;
	klong				timestamp;
};

// file wrap tail
struct qbFwHsTail
{
	kuint				hdr;
	kushort				version;
	kushort				revision;
};

// file wrap item for HS
struct qbFwHsItem
{
	kuint				hdr;
	kushort				type;
	kushort				version;
	kuint				length;
	kuint				reserved;
};

//
namespace qgFwSupp
{
	KAPI bool CheckHeadAndTail(kStream* stm);
	KAPI bool CheckHeadAndTail(kconstpointer data, kint size);
}

// HS item
enum qgHsItem
{
	QGHI_HXP = 0x1005,
};

// file service class
enum qgFsClass
{
	QGFSCL_1,
	QGFSCL_2,
	QGFSCL_3,
	QGFSCL_MAX_VALUE,
	QGFSCL_FORCE = 0xFFFF,
};

// file service reader
struct qbFsReader
{
	KCH_AVOID_FOR_INTERFACE(qbFsReader);

	virtual void Dispose() = 0;
	virtual bool Test(kconstpointer data, kint size) = 0;
	virtual bool Read(kObj* ctnr, kconstpointer data, kint size, kint mask) = 0;
};

// file service writer
struct qbFsWriter
{
	KCH_AVOID_FOR_INTERFACE(qbFsWriter);

	virtual void Dispose() = 0;
	virtual bool Test(const char* ext) = 0;
	virtual bool Write(kStream* st, kObj* ctnr, kint mask) = 0;
};


//////////////////////////////////////////////////////////////////////////
// stubs

// flags (device & stub)
#define QGSDF_FULL						0x0001
#define QGSDF_LAYOUT					0x0002
#define QGSDF_NOTITLE					0x0004
#define QGSDF_LATENCY					0x0008
#define QGSDF_PROFILE					0x0040
#define QGSDF_AUTO						0x0080		// DEBUG ONLY
#define QGSDF_MSAA						0x0200
#define QGSDF_DITHER					0x0400		// Dithering 16 bpp for DX9, OPENGL ONLY
#define QGSDF_BGRA						0x1000
#define QGSDF_INDP						0x4000
#define QGSDF_INFO						0x8000

// insi (device & stub)
#define QGSDI_ACTIVE					0x0001
#define QGSDI_VIRTUAL					0x0002
#define QGSDI_LAYOUT					0x0004
#define QGSDI_DROP						0x0008
#define QGSDI_CURSOR					0x0010
#define QGSDI_SCRSAVE					0x0020
#define QGSDI_GOPU						0x0100
#define QGSDI_EXF_1						0x0400
#define QGSDI_EXF_2						0x0800
#define QGSDI_ACS						0x1000
#define QGSDI_PAUSE						0x4000
#define QGSDI_EXIT						0x8000

//
struct qbSevHandler
{
	virtual bool OnSystem(kpointer handle, kuintptr param1, kuintptr param2, kint mesg) { return true; }
	virtual bool OnLayout(kint width, kint height, bool maximize) { return true; }
	virtual bool OnCursor() { return true; }
	virtual bool OnMouseMove(kint x, kint y, const tpl::Point& relative, kushort state) { return true; }
	virtual bool OnMouseDown(kint x, kint y, kushort button) { return true; }
	virtual bool OnMouseUp(kint x, kint y, kushort button) { return true; }
	virtual bool OnMouseDouble(kint x, kint y, kushort button) { return true; }
	virtual bool OnMouseWheel(kshort delta) { return true; }
	virtual bool OnKeyDown(kbyte key, kbyte sub, kuint ch, bool repeat, kushort state) { return true; }
	virtual bool OnKeyUp(kbyte key, kbyte extend, kushort state) { return true; }
	virtual bool OnChar(kint ch, bool repeat) { return true; }
	virtual bool OnActivate(bool action, float advance) { return true; }
	virtual bool OnDragDrop(const tpl::vector<tpl::string>& list) { return true; }
};

// stub, abstract
class KAPI qgStub : public kObj
{
	KCH_SUBCLASS(qgStub, kObj);
	KCH_FRIEND(qgRdh);

protected:
	kuint				_flags;
	kuint				_insts;

	kSpinLock			_lock;

	kint				_delay;
	kuintptr			_polls;

	float				_advance[4];
	double				_runtime;
	double				_runfps;

	tpl::Rect			_bound;
	tpl::Point			_size;
	tpl::Point			_limit;

	qgUimMouse			_mouse;
	qgUimKey			_key;

	tpl::string			_btitle;
	kpointer			_handle;

	kTimer*				_timer;
	kMount*				_mount;

	tpl::vector<qbSevHandler*>	_sehs;

	tpl::vector<qbFsReader*>	_fsrd[QGFSCL_MAX_VALUE];
	tpl::vector<qbFsWriter*>	_fswt[QGFSCL_MAX_VALUE];

public:
	static qgStub*		Instance;

protected:
	qgStub();
	~qgStub();

public:
	virtual bool Poll(kpointer osstate);

	virtual bool Layout();
	virtual void Reset() {}

	virtual bool GetControllerInput(kint slot, qgUimControllerInput* i);
	virtual bool GetControllerInfo(kint slot, qgUimControllerInfo* n);

	virtual void SetKeyDown(kbyte key, bool isdown);
	virtual bool SetControllerEnable(bool v);
	virtual bool SetControllerVibration(kint slot, const qgUimControllerVibration& v);

	virtual void SetDropEnable(bool v);
	virtual void SetAcsEnable(bool v);
	virtual void SetImeEnable(bool v);

	virtual bool SetTitle(const char* text);
	virtual void SetLimitSize(kint width, kint height);

	virtual void HoldMouse(bool v);

	bool Run(kpointer osstate);

	bool GetMouse(qgUimMouse* v);
	bool GetKey(qgUimKey* ptr);
	bool IsKeyDown(kbyte key);
	const tpl::string& GetTitleString() { return _btitle; }
	const char* GetTitlePtr() { return _btitle.c_str(); }

	void AddHandler(qbSevHandler* h);
	bool RemoveHandler(qbSevHandler* h);

	void RegisterReader(qgFsClass slt, qbFsReader* ptr);
	bool PerformRead(kObj* ctnr, kconstpointer data, kint size, kint flags, qgFsClass slt = QGFSCL_FORCE);

	void RegisterWriter(qgFsClass slt, qbFsWriter* ptr);
	bool PerformWrite(kStream* st, kObj* ctnr, kint flags, qgFsClass slt = QGFSCL_FORCE);

	kpointer GetHandle() { return _handle; }
	kint GetFlags(kint mask = 0) { return K_OMASK(_flags, mask); }
	kint GetInsts(kint mask = 0) { return K_OMASK(_insts, mask); }

	const tpl::Rect& GetBound() { return _bound; }
	const tpl::Point& GetSize() { return _size; }

	kMount* GetMount() { return _mount; }
	kTimer* GetTimer() { return _timer; }
	double GetRunFps() { return _runfps; }
	double GetRunTime() { return _runtime; }
	float GetAdvance() { return _advance[0]; }
	float GetAdvance(kint nth) { return (ksize_t)nth < 4 ? _advance[nth] : 0.0f; }

	void SetDelay(kint value) { _delay = K_CLAMP(value, 1, 1000); }
	kint GetDelay() { return _delay; }

	kint Mount(const char* path = NULL, bool autoarchive = true);
	kStream* FileOpen(const char* filename, bool indirect) { return indirect ? kMount::FileOpenIndirect(_mount, filename) : kMount::FileOpen(_mount, filename); }
	kpointer FileRead(const char* filename, kint* size) { return kMount::FileRead(_mount, filename, size); }
	kchar* FilePath(const char* path) { return kMount::BuildPath(_mount, path); }

protected:
	virtual bool _Close();
	bool _ProcessMultiClick(kint button, kint method);

public:
	static const char* GetInternalClassName();
	static void SetInternalClassName(const char* name);

public:
	static qgStub* New(const kRt& bound, const char* text, kpointer app, kint flags);
	static qgStub* New(kint width, kint height, const char* text, kpointer app, kint flags);
	static qgStub* NewVirtual(kpointer handle);
};


//////////////////////////////////////////////////////////////////////////
// image

// file type
enum qgImageFileType
{
	QGIMAGEFILE_BMP,
	QGIMAGEFILE_PNG,
	QGIMAGEFILE_JPG,
};

//
class KAPI qgImage : public kObj
{
	KCH_SUBCLASS(qgImage, kObj);

private:
	qbPixelProp			_prop;
	kint				_pitch;
	kint				_width;
	kint				_height;

	bool				_alloc;
	kint				_size;
	kpointer			_data;

protected:
	qgImage() {};
	qgImage(kint width, kint height, qgColorFormat fmt);
	qgImage(kint width, kint height, qgColorFormat fmt, kpointer data, kint size, bool alloc = true);
	~qgImage();

public:
	void Initialize(kint width, kint height, qgColorFormat fmt);
	void Initialize(kint width, kint height, qgColorFormat fmt, kpointer data, kint size, bool alloc = true);
	void Dispose();

	const qbPixelProp& GetPixelProp() { return _prop; }
	qgColorFormat GetColorFormat() { return _prop.fmt; }
	kint GetBpp() { return _prop.bpp; }
	kint GetPitch() { return _pitch; }
	kint GetWidth() { return _width; }
	kint GetHeight() { return _height; }
	kint GetSize() { return _size; }
	kpointer GetData() { return _data; }

	kuint GetPixel(kint x, kint y);
	kuint GetBox(kint x, kint y, kint w, kint h, kint bias);	// pixel box

	void SetPixel(kint x, kint y, const tpl::ColorValue& color, bool testblend = false);

	void CopyTo(qgImage* target);
	void CopyTo(qgImage* target, const tpl::Point& pos);
	void CopyToSub(qgImage* target, const tpl::Point& pos, const tpl::Rect& srect);
	void CopyToSub(qgImage* target, const tpl::Point& pos, const tpl::Rect& srect, const tpl::Rect& clip);
	void CopyToAlpha(qgImage* target, const tpl::ColorValue& cc, const tpl::Point& pos, const tpl::Rect& srect);
	void CopyToAlpha(qgImage* target, const tpl::ColorValue& cc, const tpl::Point& pos, const tpl::Rect& srect, const tpl::Rect& clip);
	void CopyToScale(qgImage* target);
	void CopyToScaleFilter(qgImage* target, kint bias, bool blend = false);
	void CopyToScaleRaw(kpointer data, kint width, kint height, qgColorFormat fmt, kint pitch);
	void Fill(const tpl::ColorValue& cc);

	bool SaveRaw(const char* filename);
};


//////////////////////////////////////////////////////////////////////////
// render object

// render object
class KAPI qgRdo : public qgObj
{
	KCH_SUBCLASS(qgRdo, qgObj);
	KT_DECL_CTOR(qgRdo);
};

// depth stencil
class KAPI qgDhsl : public qgRdo
{
	KCH_SUBCLASS(qgDhsl, qgRdo);
	KT_DECL_CTOR(qgDhsl);
};

// rasterize
class KAPI qgRasz : public qgRdo
{
	KCH_SUBCLASS(qgRasz, qgRdo);
	KT_DECL_CTOR(qgRasz);
};

// blend
class KAPI qgBlnd : public qgRdo
{
	KCH_SUBCLASS(qgBlnd, qgRdo);
	KT_DECL_CTOR(qgBlnd);
};

// sampler
class KAPI qgSplr : public qgRdo
{
	KCH_SUBCLASS(qgSplr, qgRdo);
	KT_DECL_CTOR(qgSplr);
};

// shader, abstract
class KAPI qgShader : public qgRdo
{
	KCH_SUBCLASS(qgShader, qgRdo);
	KT_DECL_CTOR(qgShader);

public:
	typedef std::function<bool(kint, const qbShaderVar*, qgShader*)> IntrFunction;

protected:
	IntrFunction		_intr;

public:
	virtual bool BindFile(qgShaderType type, const char* filename, kint flags) = 0;
	virtual bool BindData(qgShaderType type, kconstpointer data, kint size, kint flags) = 0;
	virtual bool BindShader(qgShaderType type, qgShader* shd) = 0;
	virtual bool BindShader(qgShaderType type, const char* name) = 0;

	virtual void AddCondition(const char* str) = 0;
	virtual void ClearConditions() = 0;

	virtual bool Link() = 0;

	void SetInterruptFunction(const IntrFunction& func) { _intr = func; }
};

// layout, abstract
class KAPI qgVertexLayout : public qgRdo
{
	KCH_SUBCLASS(qgVertexLayout, qgRdo);
	KT_DECL_CTOR(qgVertexLayout);

protected:
	kint				_stride;
	kushort				_stage[QGSGVERT_MAX_VALUE];

public:
	kint GetStride() { return _stride; }
	kushort GetStageStride(kint stage) { return (ksize_t)stage < 4 ? _stage[stage] : 0; }
};

// buffer, abstract
class KAPI qgBuffer : public qgRdo
{
	KCH_SUBCLASS(qgBuffer, qgRdo);
	KT_DECL_CTOR(qgBuffer);

protected:
	qgBufferType		_type : 16;
	kushort				_stride;
	kint				_size;

public:
	virtual kpointer Map(kint flags = 0) = 0;
	virtual bool Unmap() = 0;

	qgBufferType GetType() { return _type; }
	kushort GetStride() { return _stride; }
	kint GetSize() { return _size; }

	bool SetData(kconstpointer data, kint size = 0);

	//
	static bool SetIndices(qgBuffer* buf, kconstpointer data, kint count, bool is32bit);
	static bool SetVertices(qgBuffer* buf, kconstpointer data, kint count);
};

// depth buffer, abstract
class KAPI qgDepthBuffer : public qgRdo
{
	KCH_SUBCLASS(qgDepthBuffer, qgRdo);
	KT_DECL_CTOR(qgDepthBuffer);

protected:
	kuint				_width;
	kuint				_height;

public:
	kuint GetWidth() { return _width; }
	kuint GetHeight() { return _height; }
};

// motion interface
class qbAnimTexture
{
public:
	virtual kint GetCount() = 0;
	virtual kint GetFps() = 0;
	virtual kint GetIndex() = 0;
	virtual float GetLength() = 0;
	virtual float GetAdvance() = 0;
	virtual bool IsLoop() = 0;
	virtual bool IsPlay() = 0;

	virtual void SetFixedLength(float len) = 0;
	virtual void SetFps(kint v) = 0;
	virtual void SetFrameRange(kint min, kint max) = 0;
	virtual void SetPosition(float pos) = 0;
	virtual void SetPlayMode(bool isplay) = 0;
	virtual void TurnLoop(bool isloop) = 0;
	virtual void Reset() = 0;

	//
	virtual bool ManualMotionUpdate(float adv, bool& res, kuintptr& ptr) = 0;
	virtual bool MotionUpdate(float adv) = 0;
	virtual qgImage* MotionImage(kint index = -1) = 0;
};

// off texture interface
class qbOffTexture
{
public:
	virtual bool Enter(kint clearance = 0xFF, const tpl::ColorValue& color = tpl::ColorValues::Black, float depth = 1.0f, kuint stencil = 0) = 0;
	virtual bool Leave() = 0;
};

// texture, abstract
class KAPI qgTexture : public qgRdo
{
	KCH_SUBCLASS(qgTexture, qgRdo);
	KT_DECL_CTOR(qgTexture);

protected:
	struct InstData
	{
		bool			alpha : 1;
		bool			dynamic : 1;
		bool			mip_has : 1;
		bool			mip_auto : 1;
		bool			adj_clamp : 1;
		bool			adj_pow2 : 1;
		bool			adj_sqr : 1;
		bool			image_keep : 1;
		bool			beta_off : 1;
		bool			beta_anim : 1;
		bool			anim_cache : 1;
		kbyte			reserved : 5;
	};

protected:
	qgTextureType		_type : 16;
	kushort				_mips;

	qgColorFormat		_fmt;
	kuint				_width;
	kuint				_height;
	kuint				_depth;

	InstData			_insts;

public:
	virtual bool Map(qbTextureMap* map, kint flag, kint mips = 0, kint sliceface = 0) = 0;
	virtual bool Unmap() = 0;

	virtual qbAnimTexture* GetAnimation() { return NULL; }
	virtual qbOffTexture* GetOff() { return NULL; }

	qgTextureType GetType() { return _type; }
	qgColorFormat GetColorFormat() { return _fmt; }
	kuint GetMipCount() { return _mips; }
	kuint GetWidth() { return _width; }
	kuint GetHeight() { return _height; }
	kuint GetDepth() { return _depth; }

	bool HasAlpha() { return _insts.alpha; }
	bool HasMips() { return _insts.mip_has; }
	bool IsOff() { return _insts.beta_off; }
	bool IsAnimation() { return _insts.beta_anim; }
};


//////////////////////////////////////////////////////////////////////////
// resource initializer

// rasterizer state initialize
struct qbRaszInitializer
{
	qbRaszInitializer(qgFill fill = QGFILL_SOLID, qgCull cull = QGCULL_NONE, float dbias = 0.0f, float slsl = 0.0f)
	{
		RaszData.fill = fill;
		RaszData.cull = cull;
		RaszData.depth_bias = dbias;
		RaszData.slope_scale = slsl;
	}

	qbRaszData RaszData;
};

// blend state initialize
struct qbBlndInitializer
{
	qbBlndInitializer(
		qgColorMask r0mask = QGCM_RGBA,
		qgBlendOp r0cop = QGBLO_ADD,
		qgBlendFactor r0csrc = QGBLF_ONE,
		qgBlendFactor r0cdest = QGBLF_ZERO,
		qgBlendOp r0aop = QGBLO_ADD,
		qgBlendFactor r0asrc = QGBLF_ONE,
		qgBlendFactor r0adest = QGBLF_ZERO,
		//
		qgColorMask r1mask = QGCM_RGBA,
		qgBlendOp r1cop = QGBLO_ADD,
		qgBlendFactor r1csrc = QGBLF_ONE,
		qgBlendFactor r1cdest = QGBLF_ZERO,
		qgBlendOp r1aop = QGBLO_ADD,
		qgBlendFactor r1asrc = QGBLF_ONE,
		qgBlendFactor r1adest = QGBLF_ZERO,
		//
		qgColorMask r2mask = QGCM_RGBA,
		qgBlendOp r2cop = QGBLO_ADD,
		qgBlendFactor r2csrc = QGBLF_ONE,
		qgBlendFactor r2cdest = QGBLF_ZERO,
		qgBlendOp r2aop = QGBLO_ADD,
		qgBlendFactor r2asrc = QGBLF_ONE,
		qgBlendFactor r2adest = QGBLF_ZERO,
		//
		qgColorMask r3mask = QGCM_RGBA,
		qgBlendOp r3cop = QGBLO_ADD,
		qgBlendFactor r3csrc = QGBLF_ONE,
		qgBlendFactor r3cdest = QGBLF_ZERO,
		qgBlendOp r3aop = QGBLO_ADD,
		qgBlendFactor r3asrc = QGBLF_ONE,
		qgBlendFactor r3adest = QGBLF_ZERO)
	{
		BlndData[0].mask = r0mask;
		BlndData[0].color_op = r0cop;
		BlndData[0].color_src = r0csrc;
		BlndData[0].color_dest = r0cdest;
		BlndData[0].alpha_op = r0aop;
		BlndData[0].alpha_src = r0asrc;
		BlndData[0].alpha_dest = r0adest;
#if !_SB_MOBILE_
		//
		BlndData[1].mask = r1mask;
		BlndData[1].color_op = r1cop;
		BlndData[1].color_src = r1csrc;
		BlndData[1].color_dest = r1cdest;
		BlndData[1].alpha_op = r1aop;
		BlndData[1].alpha_src = r1asrc;
		BlndData[1].alpha_dest = r1adest;
		//
		BlndData[2].mask = r2mask;
		BlndData[2].color_op = r2cop;
		BlndData[2].color_src = r2csrc;
		BlndData[2].color_dest = r2cdest;
		BlndData[2].alpha_op = r2aop;
		BlndData[2].alpha_src = r2asrc;
		BlndData[2].alpha_dest = r2adest;
		//
		BlndData[3].mask = r3mask;
		BlndData[3].color_op = r3cop;
		BlndData[3].color_src = r3csrc;
		BlndData[3].color_dest = r3cdest;
		BlndData[3].alpha_op = r3aop;
		BlndData[3].alpha_src = r3asrc;
		BlndData[3].alpha_dest = r3adest;
#endif
		//
		UseIndependent = true;
	}

	qbBlndInitializer(const qbBlndData& r0)
	{
		BlndData[0] = r0;
#if !_SB_MOBILE_
		//
		BlndData[1].mask = QGCM_RGBA;
		BlndData[1].color_op = QGBLO_ADD;
		BlndData[1].color_src = QGBLF_ONE;
		BlndData[1].color_dest = QGBLF_ZERO;
		BlndData[1].alpha_op = QGBLO_ADD;
		BlndData[1].alpha_src = QGBLF_ONE;
		BlndData[1].alpha_dest = QGBLF_ZERO;
		//
		BlndData[2].mask = QGCM_RGBA;
		BlndData[2].color_op = QGBLO_ADD;
		BlndData[2].color_src = QGBLF_ONE;
		BlndData[2].color_dest = QGBLF_ZERO;
		BlndData[2].alpha_op = QGBLO_ADD;
		BlndData[2].alpha_src = QGBLF_ONE;
		BlndData[2].alpha_dest = QGBLF_ZERO;
		//
		BlndData[3].mask = QGCM_RGBA;
		BlndData[3].color_op = QGBLO_ADD;
		BlndData[3].color_src = QGBLF_ONE;
		BlndData[3].color_dest = QGBLF_ZERO;
		BlndData[3].alpha_op = QGBLO_ADD;
		BlndData[3].alpha_src = QGBLF_ONE;
		BlndData[3].alpha_dest = QGBLF_ZERO;
#endif
		//
		UseIndependent = false;
	}

	qbBlndInitializer(const qbBlndData* rs, kint count)
	{
		for (kint i = 0; i < count; i++)
			BlndData[i] = rs[i];

		for (kint i = count; i < QGSGOFF_MAX_VALUE; i++)
		{
			BlndData[i].mask = QGCM_RGBA;
			BlndData[i].color_op = QGBLO_ADD;
			BlndData[i].color_src = QGBLF_ONE;
			BlndData[i].color_dest = QGBLF_ZERO;
			BlndData[i].alpha_op = QGBLO_ADD;
			BlndData[i].alpha_src = QGBLF_ONE;
			BlndData[i].alpha_dest = QGBLF_ZERO;
		}

		UseIndependent = count > 1;
	}

	template <ksize_t COUNT>
	qbBlndInitializer(const qbBlndData(&rs)[COUNT])
	{
		for (kint i = 0; i < COUNT; i++)
			BlndData[i] = rs[i];

		for (kint i = COUNT; i < QGSGOFF_MAX_VALUE; i++)
		{
			BlndData[i].mask = QGCM_RGBA;
			BlndData[i].color_op = QGBLO_ADD;
			BlndData[i].color_src = QGBLF_ONE;
			BlndData[i].color_dest = QGBLF_ZERO;
			BlndData[i].alpha_op = QGBLO_ADD;
			BlndData[i].alpha_src = QGBLF_ONE;
			BlndData[i].alpha_dest = QGBLF_ZERO;
		}

		UseIndependent = COUNT > 1;
	}

	qbBlndData BlndData[QGSGOFF_MAX_VALUE];
	bool UseIndependent;
};

// sampler state initialize
struct qbSplrInitializer
{
	qbSplrInitializer(
		qgFilter filt = QGFLTX_POINT,
		qgAddress addru = QGADR_CLAMP,
		qgAddress addrv = QGADR_CLAMP,
		qgAddress addrw = QGADR_CLAMP,
		kint lbias = 0,
		const tpl::ColorValue& bcv = tpl::ColorValues::Transparent,
		qgCmpOp cop = QGCOP_NEVER)
	{
		SplrData.filt = filt;
		SplrData.addru = addru;
		SplrData.addrv = addrv;
		SplrData.addrw = addrw;
		SplrData.cop = cop;
		SplrData.bcv = bcv;
		SplrData.lod_bias = lbias;
		SplrData.lod_range = tpl::Vec2(0.0f, FLT_MAX);
	}

	qbSplrData SplrData;
};

// depth stencil state initialize
struct qbDhslInitializer
{
	qbDhslInitializer(
		bool depth_write = true,
		qgCmpOp depth_func = QGCOP_LEQ,
		bool front_enable = false,
		qgCmpOp front_func = QGCOP_ALWAYS,
		qgStencilOp front_pass = QGSOP_KEEP,
		qgStencilOp front_fail = QGSOP_KEEP,
		qgStencilOp front_depth_fail = QGSOP_KEEP,
		bool back_enable = false,
		qgCmpOp back_func = QGCOP_ALWAYS,
		qgStencilOp back_pass = QGSOP_KEEP,
		qgStencilOp back_fail = QGSOP_KEEP,
		qgStencilOp back_depth_fail = QGSOP_KEEP,
		kbyte mask_read = 0xFF,
		kbyte mask_write = 0xFF)
	{
		DhslData.depth_write = depth_write;
		DhslData.depth_func = depth_func;

		DhslData.front_enable = front_enable;
		DhslData.front_func = front_func;
		DhslData.front_pass = front_pass;
		DhslData.front_fail = front_fail;
		DhslData.front_depth_fail = front_depth_fail;

		DhslData.back_enable = back_enable;
		DhslData.back_func = back_func;
		DhslData.back_pass = front_pass;
		DhslData.back_fail = front_fail;
		DhslData.back_depth_fail = front_depth_fail;

		DhslData.mask_read = mask_read;
		DhslData.mask_write = mask_write;
	}

	qbDhslData DhslData;
};


//////////////////////////////////////////////////////////////////////////
// device
class KAPI qgRdh : public kObj
{
	KCH_SUBCLASS(qgRdh, kObj);
	KCH_FRIEND(qgObj);

public:
	// device update info
	struct Nfo
	{
		kuintptr			frames;
		kuintptr			invokes;
		kuintptr			creations;
		kuintptr			disposes;
		kuintptr			states;
		kuintptr			shaders;
		kuintptr			textures;
		kuintptr			renderers;
		kuintptr			transforms;
		kuintptr			drawcalls;
		kuintptr			vertices;
		bool				flush;
	};

	// device capabilities
	struct Caps
	{
		char				name[64];						// renderer name
		char				vendor[64];						// renderer vendor

		kuint				version;						// renderer version
		kuint				version_shader;					// shader version

		bool				supp_occlusion;					// occlusion ambient?

		kuint				max_texture_dimension;			// maximum texture dimension
		kuint				max_texture_count;				// maximum texture count
		kuint				max_offtex_count;				// maximum offscreen texture count
		kint				texture_image_flag;				// image flag for texture
	};

	// device present variables
	struct Prsn
	{
		// trfm
		tpl::Mat4			t_tm[QGTM_MAX_VALUE];			// transform matrix
		tpl::Mat4			t_vipr;							// view * proj
		tpl::Mat4			t_invv;							// inverse view
		tpl::Mat4			t_otm;							// ortho transform matrix
		tpl::Mat4			t_tfm;							// texture formation matrix

		tpl::Point			t_sdm;							// screen dimension
		qbViewPort			t_vp;							// view port

		// color
		tpl::Color			cr_bg;							// background

		// wedge
		kint				pw_cnt;							// wedge/bone count
		const tpl::Mat4*	pw_pcb;							// wedge/bone matrices

		// property
		tpl::Vec4			ps_v[4];						// shader property (vector)
		tpl::Mat4			ps_m[4];						// shader property (matrix)
	};


protected:
	qgStub*				_stub;			// application stub
	kSpinLock			_lock;			// management lock;

	Nfo					_nfo;			// information
	Caps				_caps;			// capability
	Prsn				_prsn;			// present

public:
	static qgRdh*		Instance;		// GLOBAL INSTANCE

protected:
	qgRdh();
	~qgRdh();

public:
	bool Run(kpointer osstate);

	qgStub* GetStub() { return _stub; }
	const Nfo& GetNfo() { return _nfo; }
	const Caps& GetCaps() { return _caps; }
	const Prsn& GetPrsn() { return _prsn; }
	const qbViewPort& GetViewport() { return _prsn.t_vp; }

	void SetPropVec4(kint n, const tpl::Vec4& v);
	void SetPropMat4(kint n, const tpl::Mat4& m);
	void SetPropWedge(kint cnt, const tpl::Mat4* pcb);

public:
	const char* GetDeviceName();

	// stub
	virtual bool Layout(kint width, kint height);
	virtual void Reset() {}

	//
	virtual bool Enter(kint clearance = 0xFF);
	virtual bool Leave();
	virtual bool Flush();

	virtual void ClearMRTs(kint clearance, kint colorcount, const tpl::ColorValue* colors, float depth = 1.0f, kuint stencil = 0);

	// resource
	virtual void SetBackground(const tpl::ColorValue& color);
	virtual bool SetTM(qgTmType tm, const tpl::Mat4& m);
	virtual void SetViewport(kint x, kint y, kint w, kint h, float minz, float maxz);
	virtual void SetScissor(bool enable, const tpl::Rect& area) = 0;

	virtual void SetDhsl(qgDhsl* dhsl) = 0;
	virtual void SetRasz(qgRasz* rasz) = 0;
	virtual void SetBlnd(qgBlnd* blnd) = 0;
	virtual void SetSplr(kint stage, qgSplr* splr) = 0;

	virtual void SetShader(qgShader* shd, qgVertexLayout* lo) = 0;
	virtual void SetBufferVertex(kint stage, qgBuffer* buf) = 0;
	virtual void SetBufferIndex(qgBuffer* buf) = 0;

	virtual void SetTexture(kint stage, qgTexture* tex) = 0;
	virtual void SetRenderTargets(kint count, qgTexture** tex) = 0;

	// draw 
	virtual void Draw(qgTopology tpg, kint verts) = 0;
	virtual void DrawIndexed(qgTopology tpg, kint indices) = 0;

	//
	virtual void DrawSprite(const tpl::Rect& bound, const tpl::ColorValue& color, qgTexture* tex = NULL, const tpl::Quad* coord = NULL) = 0;
	virtual void DrawLines(bool ortho, bool strip, kint count, const tpl::Vec3* pts, const tpl::ColorValue* colors) = 0;
	virtual void DrawStrips(bool ortho, kint count, const tpl::Vec3* pts, const tpl::ColorValue* colors, qgTexture* tex = NULL, const tpl::Vec2* coords = NULL) = 0;

	//
	virtual void PrimitiveBegin(qgTopology tpg, kint verts, kint stride, kpointer* data) = 0;
	virtual void PrimitiveEnd() = 0;
	virtual void PrimitiveBeginIndexed(qgTopology tpg, kint verts, kint vertstride, kpointer* vertdata, kint indices, kint indstride, kpointer* inddata) = 0;
	virtual void PrimitiveEndIndexed() = 0;
	void PrimitiveDraw(qgTopology tpg, kint verts, kint stride, kconstpointer data);
	void PrimitiveDrawIndexed(qgTopology tpg, kint verts, kint vertstride, kconstpointer vertdata, kint indices, kint indstride, kconstpointer inddata);

	//
	virtual void GlyphBegin(qgShader* shd) = 0;
	virtual void GlyphDraw(kint x, kint y, kint w, kint h, const tpl::ColorValue& color, qgTexture* tex) = 0;
	virtual void GlyphEnd() = 0;

	//
	virtual qgRasz* CreateRasz(const qbRaszInitializer& inz) = 0;
	virtual qgBlnd* CreateBlnd(const qbBlndInitializer& inz) = 0;
	virtual qgSplr* CreateSplr(const qbSplrInitializer& inz) = 0;
	virtual qgDhsl* CreateDhsl(const qbDhslInitializer& inz) = 0;
	virtual qgShader* CreateShader(const char* name) = 0;
	virtual qgTexture* CreateTexture(const char* key) = 0;
	virtual qgTexture* CreateTexture2(const char* key, qgImage* img, kint flags) = 0;
	virtual qgTexture* CreateTexture2(qgColorFormat fmt, kuint width, kuint height, kuint mips, kint flags, const char* key) = 0;
	virtual qgTexture* CreateTexture3(qgColorFormat fmt, kuint width, kuint height, kuint depth, kuint mips, kint flags, const char* key) = 0;
	virtual qgTexture* CreateTextureCube(qgColorFormat fmt, kuint size, kuint mips, kint flags, const char* key) = 0;
	virtual qgTexture* CreateAnimTexture(const char* filename, bool allocate = false) = 0;
	virtual qgVertexLayout* CreateLayout(kint count, const qbLayoutElement* data) = 0;
	virtual qgDepthBuffer* CreateDepthBuffer(kuint width, kuint height) = 0;
	virtual qgBuffer* CreateBuffer(qgBufferType type, kint stride, kint size, kint flags, kconstpointer data) = 0;

protected:
	virtual bool _Initialize(qgStub* stub, kint flags);
	virtual bool _ResetPrepare(const tpl::Point& size, bool prepare);
	virtual void _Finalize();

public:
	static qgRdh* New(const char* dev, const tpl::Rect& bound, kint flags, const char* title, kpointer app);
	static qgRdh* New(const char* dev, kint width, kint height, kint flags, const char* title, kpointer app);
	static qgRdh* NewVirtual(const char* dev, kpointer handle, kint flags);
};

//
namespace qgRdhSupp
{
	template <ksize_t COUNT>
	inline void DrawLines(bool ortho, bool strip, const tpl::Vec3(&pts)[COUNT])
	{
		qgRdh::Instance->DrawLines(ortho, strip, COUNT, pts, NULL);
	}

	template <ksize_t COUNT>
	inline void DrawLines(bool ortho, bool strip, const tpl::Vec3(&pts)[COUNT], const tpl::ColorValue(&colors)[COUNT])
	{
		qgRdh::Instance->DrawLines(ortho, strip, COUNT, pts, colors);
	}

	//
	template <ksize_t COUNT>
	inline void DrawStrips(bool ortho, const tpl::Vec3(&pts)[COUNT], const tpl::ColorValue(&colors)[COUNT], const tpl::Vec2(&coords)[COUNT], qgTexture* tex)
	{
		qgRdh::Instance->DrawStrips(ortho, COUNT, pts, colors, tex, coords);
	}

	template <ksize_t COUNT>
	inline void DrawStrips(bool ortho, const tpl::Vec3(&pts)[COUNT], const tpl::ColorValue(&colors)[COUNT], qgTexture* tex = NULL)
	{
		qgRdh::Instance->DrawStrips(ortho, COUNT, pts, colors, tex, NULL);
	}

	template <ksize_t COUNT>
	inline void DrawStrips(bool ortho, const tpl::Vec3(&pts)[COUNT], const tpl::Vec2(&coords)[COUNT], qgTexture* tex)
	{
		qgRdh::Instance->DrawStrips(ortho, COUNT, pts, NULL, tex, coords);
	}

	template <ksize_t COUNT>
	inline void DrawStrips(bool ortho, const tpl::Vec3(&pts)[COUNT])
	{
		qgRdh::Instance->DrawStrips(ortho, COUNT, pts, NULL, NULL, NULL);
	}

	//
	template <ksize_t COUNT>
	inline qgVertexLayout* CreateLayout(const qbLayoutElement(&elms)[COUNT])
	{
		return qgRdh::Instance->CreateLayout((kint)COUNT, elms);
	}

	//
	template <ksize_t COUNT>
	inline qgBuffer* CreateBufferIndex(const kuint(&data)[COUNT], kint flags)
	{
		return qgRdh::Instance->CreateBufferIndex((kint)COUNT, data, flags);
	}

	template <ksize_t COUNT>
	inline qgBuffer* CreateBufferIndex(const kushort(&data)[COUNT], kint flags)
	{
		return qgRdh::Instance->CreateBufferIndex((kint)COUNT, data, flags);
	}

	//
	template <typename ELEMENT, ksize_t COUNT>
	inline qgBuffer* CreateBufferVertex(qgVertexLayout* lo, kint stage, const ELEMENT(&data)[COUNT], kint flags)
	{
		return qgRdh::Instance->CreateBufferVertex(lo, stage, (kint)COUNT, data, flags);
	}

	template <typename ELEMENT, ksize_t COUNT>
	inline qgBuffer* CreateBufferVertex(const ELEMENT(&data)[COUNT], kint flags)
	{
		return qgRdh::Instance->CreateBufferVertex((kint)sizeof(ELEMENT), (kint)COUNT, data, flags);
	}
}


//////////////////////////////////////////////////////////////////////////
// static render resource

//
template <typename INITTYPE, typename BASETYPE>
struct qbStaticRdo
{
	typedef tpl::BasePtr<BASETYPE> REFTYPE;

	static REFTYPE GetPtr() throw()
	{
		static InternalStaticRes Res;

		return Res.PTR;
	}

private:
	class InternalStaticRes
	{
	public:
		BASETYPE* PTR;

		InternalStaticRes() throw()
		{
			PTR = INITTYPE::CreatePtr();
		}

		~InternalStaticRes() throw()
		{
		}
	};
};

// static rasterizer state
template <
	qgFill fill = QGFILL_SOLID,
	qgCull cull = QGCULL_NONE
>
struct qbStaticRasz : public qbStaticRdo <
	qbStaticRasz<fill, cull>, qgRasz
>
{
	static qgRasz* CreatePtr() throw()
	{
		qbRaszInitializer inz(fill, cull, 0.0f, 0.0f);
		return qgRdh::Instance->CreateRasz(inz);
	}
};

// static blend state
template<
	qgColorMask r0mask = QGCM_RGBA,
	qgBlendOp r0cop = QGBLO_ADD,
	qgBlendFactor r0csrc = QGBLF_ONE,
	qgBlendFactor r0cdest = QGBLF_ZERO,
	qgBlendOp r0aop = QGBLO_ADD,
	qgBlendFactor r0asrc = QGBLF_ONE,
	qgBlendFactor r0adest = QGBLF_ZERO,
	//
	qgColorMask r1mask = QGCM_RGBA,
	qgBlendOp r1cop = QGBLO_ADD,
	qgBlendFactor r1csrc = QGBLF_ONE,
	qgBlendFactor r1cdest = QGBLF_ZERO,
	qgBlendOp r1aop = QGBLO_ADD,
	qgBlendFactor r1asrc = QGBLF_ONE,
	qgBlendFactor r1adest = QGBLF_ZERO,
	//
	qgColorMask r2mask = QGCM_RGBA,
	qgBlendOp r2cop = QGBLO_ADD,
	qgBlendFactor r2csrc = QGBLF_ONE,
	qgBlendFactor r2cdest = QGBLF_ZERO,
	qgBlendOp r2aop = QGBLO_ADD,
	qgBlendFactor r2asrc = QGBLF_ONE,
	qgBlendFactor r2adest = QGBLF_ZERO,
	//
	qgColorMask r3mask = QGCM_RGBA,
	qgBlendOp r3cop = QGBLO_ADD,
	qgBlendFactor r3csrc = QGBLF_ONE,
	qgBlendFactor r3cdest = QGBLF_ZERO,
	qgBlendOp r3aop = QGBLO_ADD,
	qgBlendFactor r3asrc = QGBLF_ONE,
	qgBlendFactor r3adest = QGBLF_ZERO
>
struct qbStaticBlnd : public qbStaticRdo <
	qbStaticBlnd<
	r0mask, r0cop, r0csrc, r0cdest, r0aop, r0asrc, r0adest,
	r1mask, r1cop, r1csrc, r1cdest, r1aop, r1asrc, r1adest,
	r2mask, r2cop, r2csrc, r2cdest, r2aop, r2asrc, r2adest,
	r3mask, r3cop, r3csrc, r3cdest, r3aop, r3asrc, r3adest
	>, qgBlnd
>
{
	static qgBlnd* CreatePtr() throw()
	{
		qbBlndInitializer inz(
			r0mask, r0cop, r0csrc, r0cdest, r0aop, r0asrc, r0adest,
			r1mask, r1cop, r1csrc, r1cdest, r1aop, r1asrc, r1adest,
			r2mask, r2cop, r2csrc, r2cdest, r2aop, r2asrc, r2adest,
			r3mask, r3cop, r3csrc, r3cdest, r3aop, r3asrc, r3adest);
		return qgRdh::Instance->CreateBlnd(inz);
	}
};

// static sampler state
template<
	qgFilter filt = QGFLTX_POINT,
	qgAddress addru = QGADR_CLAMP,
	qgAddress addrv = QGADR_CLAMP,
	qgAddress addrw = QGADR_CLAMP,
	kint lbias = 0,
	qgCmpOp cop = QGCOP_NEVER
>
struct qbStaticSplr : public qbStaticRdo <
	qbStaticSplr<filt, addru, addrv, addrw, lbias, cop>, qgSplr
>
{
	static qgSplr* CreatePtr() throw()
	{
		qbSplrInitializer inz(filt, addru, addrv, addrw, lbias, tpl::ColorValues::Transparent, cop);
		return qgRdh::Instance->CreateSplr(inz);
	}
};

// static depth stencil state
template<
	bool depth_write = true,
	qgCmpOp depth_func = QGCOP_LEQ,
	bool front_enable = false,
	qgCmpOp front_func = QGCOP_ALWAYS,
	qgStencilOp front_pass = QGSOP_KEEP,
	qgStencilOp front_fail = QGSOP_KEEP,
	qgStencilOp front_depth_fail = QGSOP_KEEP,
	bool back_enable = false,
	qgCmpOp back_func = QGCOP_ALWAYS,
	qgStencilOp back_pass = QGSOP_KEEP,
	qgStencilOp back_fail = QGSOP_KEEP,
	qgStencilOp back_depth_fail = QGSOP_KEEP,
	kbyte mask_read = 0xFF,
	kbyte mask_write = 0xFF
>
struct qbStaticDhsl : public qbStaticRdo <
	qbStaticDhsl<
	depth_write, depth_func,
	front_enable, front_func, front_pass, front_fail, front_depth_fail,
	back_enable, back_func, back_pass, back_fail, back_depth_fail,
	mask_read, mask_write
	>, qgDhsl
>
{
	static qgDhsl* CreatePtr() throw()
	{
		qbDhslInitializer inz(
			depth_write, depth_func,
			front_enable, front_func, front_pass, front_fail, front_depth_fail,
			back_enable, back_func, back_pass, back_fail, back_depth_fail,
			mask_read, mask_write);
		return qgRdh::Instance->CreateDhsl(inz);
	}
};

#ifdef _MSC_VER
#pragma warning(pop)
#endif

#endif	// __INC_QGACH_H__
